﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.ComponentModel;
using System.Collections.Generic;
using System.Windows.Data;
using System.IO;
using System.Linq;

using Cinch;
using MEFedMVVM.ViewModelLocator;
using MEFedMVVM.Services.Contracts;
using MEFedMVVM.Common;


namespace Anata.Client
{
    /// <summary>
    /// </summary>
    [ExportViewModel("TransaksiViewModel")]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class TransaksiViewModel : EditableValidatingViewModelBase
    {
        #region Data
        
        private ViewMode currentViewMode = ViewMode.AddMode;

        #region Data.Primitives
        private DataWrapper<Int32> idTransaksi;
        private DataWrapper<Int32?> idKonsumen;
        private String namaKonsumen;
        private String alamatKonsumen;
        private String teleponKonsumen;
        private DataWrapper<Int32?> idCabang;
        private DataWrapper<DateTime?> waktuBuat;
        private DataWrapper<DateTime?> waktuSelesai;
        //private DataWrapper<Int32> totalHarga;
        //private DataWrapper<Int32> potonganHarga;
        private DataWrapper<Int32> koreksiHarga;
        private DataWrapper<Boolean> isBatal;

        private bool isBusy = false;
        private bool isCollectionsChanged = false;
        private TransaksiThumbnailViewModel loadedTransaksiThumbnail;
        //private Transaksi loadedTransaksi;
        #endregion

        private IEnumerable<DataWrapperBase> cachedListOfDataWrappers;

        #region Data.Rules
        private static SimpleRule idKonsumenRule;
        #endregion

        #region Data.VMs
        private DispatcherNotifiedObservableCollection<TransaksiLayananViewModel> transaksiLayanans;
        private ICollectionView transaksiLayanansCV;
        private DispatcherNotifiedObservableCollection<TransaksiProdukViewModel> transaksiProduks;
        private ICollectionView transaksiProduksCV;
        private DispatcherNotifiedObservableCollection<TransaksiPembayaranViewModel> transaksiPembayarans;
        private ICollectionView transaksiPembayaransCV;
        #endregion

        #region Data.Services
        private IViewAwareStatus viewAwareStatusService;
        private IMessageBoxService messageBoxService;
        private IUIVisualizerService uiVisualizerService;
        private ITransaksiProvider transaksiProvider;
        private IReferenceProvider referenceProvider;
        #endregion

        #endregion

        #region Constructor
        [ImportingConstructor]
        public TransaksiViewModel(
            IMessageBoxService messageBoxService,
            IUIVisualizerService uiVisualizerService,
            IViewAwareStatus viewAwareStatusService,
            ITransaksiProvider transaksiProvider,
            IReferenceProvider referenceProvider)
        {
            #region Constructor.SetupServices
            this.messageBoxService = messageBoxService;
            this.uiVisualizerService = uiVisualizerService;
            this.viewAwareStatusService = viewAwareStatusService;
            this.transaksiProvider = transaksiProvider;
            this.referenceProvider = referenceProvider;
            this.viewAwareStatusService.ViewLoaded += ViewAwareStatusService_ViewLoaded;
            #endregion

            #region Constructor.SetupCommands
            KonsumenSelectCommand = new SimpleCommand<Object, Object>(CanExecuteKonsumenSelectCommand, ExecuteKonsumenSelectCommand);
            TransaksiLayananAddCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiLayananAddCommand, ExecuteTransaksiLayananAddCommand);
            TransaksiLayananCancelCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiLayananCancelCommand, ExecuteTransaksiLayananCancelCommand);
            TransaksiProdukAddCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiProdukAddCommand, ExecuteTransaksiProdukAddCommand);
            TransaksiProdukCancelCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiProdukCancelCommand, ExecuteTransaksiProdukCancelCommand);
            TransaksiPembayaranAddCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiPembayaranAddCommand, ExecuteTransaksiPembayaranAddCommand);
            TransaksiPembayaranCancelCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiPembayaranCancelCommand, ExecuteTransaksiPembayaranCancelCommand);
            TransaksiSaveCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiSaveCommand, ExecuteTransaksiSaveCommand);
            TransaksiPayCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiPayCommand, ExecuteTransaksiPayCommand);
            TransaksiCancelCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiCancelCommand, ExecuteTransaksiCancelCommand);
            TransaksiExitCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiExitCommand, ExecuteTransaksiExitCommand);
            TransaksiPayExitCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiPayExitCommand, ExecuteTransaksiPayExitCommand);
            TransaksiPayFinishCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiPayFinishCommand, ExecuteTransaksiPayFinishCommand);
            #endregion

            #region Constructor.SetupDataWrappers
            IdTransaksi = new DataWrapper<Int32>(this, idTransaksiChangeArgs);
            IdTransaksi.IsEditable = true;
            IdKonsumen = new DataWrapper<Int32?>(this, idKonsumenChangeArgs);
            IdKonsumen.IsEditable = true;
            IdCabang = new DataWrapper<Int32?>(this, idCabangChangeArgs);
            IdCabang.IsEditable = true;
            WaktuBuat = new DataWrapper<DateTime?>(this, waktuBuatChangeArgs);
            WaktuBuat.IsEditable = true;
            WaktuBuat.DataValue = DateTime.Now;
            WaktuSelesai = new DataWrapper<DateTime?>(this, waktuSelesaiChangeArgs);
            WaktuSelesai.IsEditable = true;
            //TotalHarga = new DataWrapper<Int32>(this, totalHargaChangeArgs);
            //TotalHarga.IsEditable = true;
            //PotonganHarga = new DataWrapper<Int32>(this, potonganHargaChangeArgs);
            //PotonganHarga.IsEditable = true;
            KoreksiHarga = new DataWrapper<Int32>(this, koreksiHargaChangeArgs);
            KoreksiHarga.IsEditable = true;
            IsBatal = new DataWrapper<Boolean>(this, isBatalChangeArgs);
            IsBatal.IsEditable = true;
            IsBatal.DataValue = false;
            #endregion

            //fetch list of all DataWrappers, so they can be used again later without the
            //need for reflection
            cachedListOfDataWrappers =
                DataWrapperHelper.GetWrapperProperties<TransaksiViewModel>(this);

            #region Constructor.SetupValidationRules
            idKonsumen.AddRule(idKonsumenRule);
            #endregion

            #region Constructor.SetupVMs
            TransaksiLayanans = new DispatcherNotifiedObservableCollection<TransaksiLayananViewModel>();
            TransaksiLayanansCV = CollectionViewSource.GetDefaultView(transaksiLayanans);
            TransaksiProduks = new DispatcherNotifiedObservableCollection<TransaksiProdukViewModel>();
            TransaksiProduksCV = CollectionViewSource.GetDefaultView(transaksiProduks);
            TransaksiPembayarans = new DispatcherNotifiedObservableCollection<TransaksiPembayaranViewModel>();
            TransaksiPembayaransCV = CollectionViewSource.GetDefaultView(transaksiPembayarans);
            #endregion

            Mediator.Instance.Register(this);
        }
        #endregion

        #region Statics
        static TransaksiViewModel()
        {
            idKonsumenRule = new SimpleRule("DataValue", "Konsumen harus diisi",
                      (Object domainObject)=>
                      {
                          DataWrapper<Int32?> obj = (DataWrapper<Int32?>)domainObject;
                          return obj.DataValue == null || obj.DataValue == 0;
                      });
        }

        public static int STATUS_TRANSAKSI_ON = 0;
        public static int STATUS_TRANSAKSI_OFF = 1;
        public static int STATUS_TRANSAKSI_CANCELLED = 99;
        #endregion

        #region PublicProperties
        #region Public.Commands
        public SimpleCommand<Object, Object> KonsumenSelectCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiLayananAddCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiLayananCancelCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiProdukAddCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiProdukCancelCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiPembayaranAddCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiPembayaranCancelCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiSaveCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiPayCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiCancelCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiExitCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiPayExitCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiPayFinishCommand { get; private set; }
        #endregion

        #region Public.ViewMode
        /// <summary>
        /// The current ViewMode, when changed will loop
        /// through all nested DataWrapper objects and change
        /// their state also
        /// </summary>

        static PropertyChangedEventArgs currentViewModeChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.CurrentViewMode);

        public ViewMode CurrentViewMode
        {
            get { return currentViewMode; }
            set
            {
                currentViewMode = value;

                switch (currentViewMode)
                {
                    case ViewMode.AddMode:
                        this.DisplayName = "Transaksi Baru";
                        break;
                    case ViewMode.EditMode:
                        this.DisplayName = "Ubah Transaksi";
                        break;
                    case ViewMode.ViewOnlyMode:
                        this.DisplayName = "Lihat Transaksi";
                        break;
                }

                //Now change all the CachedListOfDataWrappers
                //Which sets all the Cinch.DataWrapper<T>s to the correct IsEditable
                //state based on the new ViewMode applied to the ViewModel
                //we can use the Cinch.DataWrapperHelper class for this
                foreach (var tlvm in transaksiLayanans)
                {
                    tlvm.CurrentViewMode = currentViewMode;
                }
                foreach (var tpvm in transaksiProduks)
                {
                    tpvm.CurrentViewMode = currentViewMode;
                }
                foreach (var tbvm in transaksiPembayarans)
                {
                    tbvm.CurrentViewMode = currentViewMode;
                }

                DataWrapperHelper.SetMode(
                    CachedListOfDataWrappers,
                    currentViewMode);

                NotifyPropertyChanged(currentViewModeChangeArgs);
            }
        }
        #endregion

        #region Public.Data
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs idTransaksiChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IdTransaksi);
        public DataWrapper<Int32> IdTransaksi
        {
            get { return idTransaksi; }
            set
            {
                idTransaksi = value;
                NotifyPropertyChanged(idTransaksiChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs idKonsumenChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IdKonsumen);
        public DataWrapper<Int32?> IdKonsumen
        {
            get { return idKonsumen; }
            set
            {
                idKonsumen = value;
                NotifyPropertyChanged(idKonsumenChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs namaKonsumenChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.NamaKonsumen);
        public String NamaKonsumen
        {
            get { return namaKonsumen; }
            set
            {
                namaKonsumen = value;
                NotifyPropertyChanged(namaKonsumenChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs alamatKonsumenChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.AlamatKonsumen);
        public String AlamatKonsumen
        {
            get { return alamatKonsumen; }
            set
            {
                alamatKonsumen = value;
                NotifyPropertyChanged(alamatKonsumenChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs teleponKonsumenChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TeleponKonsumen);
        public String TeleponKonsumen
        {
            get { return teleponKonsumen; }
            set
            {
                teleponKonsumen = value;
                NotifyPropertyChanged(teleponKonsumenChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs idCabangChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IdCabang);
        public DataWrapper<Int32?> IdCabang
        {
            get { return idCabang; }
            set
            {
                idCabang = value;
                NotifyPropertyChanged(idCabangChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs waktuBuatChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.WaktuBuat);
        public DataWrapper<DateTime?> WaktuBuat
        {
            get { return waktuBuat; }
            set
            {
                waktuBuat = value;
                NotifyPropertyChanged(waktuBuatChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs waktuSelesaiChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.WaktuSelesai);
        public DataWrapper<DateTime?> WaktuSelesai
        {
            get { return waktuSelesai; }
            set
            {
                waktuSelesai = value;
                NotifyPropertyChanged(waktuSelesaiChangeArgs);
            }
        }
        ///// <summary>
        ///// </summary>
        //static PropertyChangedEventArgs totalHargaChangeArgs =
        //    ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TotalHarga);
        //public DataWrapper<Int32> TotalHarga
        //{
        //    get { return totalHarga; }
        //    set
        //    {
        //        totalHarga = value;
        //        NotifyPropertyChanged(totalHargaChangeArgs);
        //    }
        //}
        ///// <summary>
        ///// </summary>
        //static PropertyChangedEventArgs potonganHargaChangeArgs =
        //    ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.PotonganHarga);
        //public DataWrapper<Int32> PotonganHarga
        //{
        //    get { return potonganHarga; }
        //    set
        //    {
        //        potonganHarga = value;
        //        NotifyPropertyChanged(potonganHargaChangeArgs);
        //    }
        //}
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs koreksiHargaChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.KoreksiHarga);
        public DataWrapper<Int32> KoreksiHarga
        {
            get { return koreksiHarga; }
            set
            {
                koreksiHarga = value;
                NotifyPropertyChanged(koreksiHargaChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs isBatalChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IsBatal);
        public DataWrapper<Boolean> IsBatal
        {
            get { return isBatal; }
            set
            {
                isBatal = value;
                NotifyPropertyChanged(isBatalChangeArgs);
            }
        }
        #endregion

        #region Public.IsBusy
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs isBusyChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IsBusy);
        public bool IsBusy
        {
            get { return isBusy; }
            set
            {
                isBusy = value;
                foreach (var item in transaksiLayanans)
                {
                    item.IsBusy = value;
                }
                foreach (var item in transaksiProduks)
                {
                    item.IsBusy = value;
                }
                foreach (var item in transaksiPembayarans)
                {
                    item.IsBusy = value;
                }
                NotifyPropertyChanged(isBusyChangeArgs);
            }
        }
        #endregion

        #region Public.Cached Collection
        /// <summary>
        /// Returns cached collection of DataWrapperBase
        /// </summary>
        public IEnumerable<DataWrapperBase> CachedListOfDataWrappers
        {
            get { return cachedListOfDataWrappers; }
        }
        #endregion

        #region Public.DataVM
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs transaksiLayanansChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TransaksiLayanans);
        public DispatcherNotifiedObservableCollection<TransaksiLayananViewModel> TransaksiLayanans
        {
            get { return transaksiLayanans; }
            set
            {
                transaksiLayanans = value;
                NotifyPropertyChanged(transaksiLayanansChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs transaksiLayanansCVChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TransaksiLayanansCV);
        public ICollectionView TransaksiLayanansCV
        {
            get { return transaksiLayanansCV; }
            set
            {
                transaksiLayanansCV = value;
                NotifyPropertyChanged(transaksiLayanansCVChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs transaksiProduksChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TransaksiProduks);
        public DispatcherNotifiedObservableCollection<TransaksiProdukViewModel> TransaksiProduks
        {
            get { return transaksiProduks; }
            set
            {
                transaksiProduks = value;
                NotifyPropertyChanged(transaksiProduksChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs transaksiProduksCVChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TransaksiProduksCV);
        public ICollectionView TransaksiProduksCV
        {
            get { return transaksiProduksCV; }
            set
            {
                transaksiProduksCV = value;
                NotifyPropertyChanged(transaksiProduksCVChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs transaksiPembayaransChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TransaksiPembayarans);
        public DispatcherNotifiedObservableCollection<TransaksiPembayaranViewModel> TransaksiPembayarans
        {
            get { return transaksiPembayarans; }
            set
            {
                transaksiPembayarans = value;
                NotifyPropertyChanged(transaksiPembayaransChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs transaksiPembayaransCVChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TransaksiPembayaransCV);
        public ICollectionView TransaksiPembayaransCV
        {
            get { return transaksiPembayaransCV; }
            set
            {
                transaksiPembayaransCV = value;
                NotifyPropertyChanged(transaksiPembayaransCVChangeArgs);
            }
        }
        #endregion

        #region Public.SummaryData
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs subTotalHargaChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.SubTotalHarga);
        public Int32 SubTotalHarga
        {
            get
            {
                Int32 sum = 0;
                foreach (TransaksiLayananViewModel tl in transaksiLayanans.Where(tl => !tl.IsBatal.DataValue))
                {
                    sum += tl.HargaLayanan;
                }
                foreach (TransaksiProdukViewModel tp in transaksiProduks.Where(tp => !tp.IsBatal.DataValue))
                {
                    sum += tp.SubTotalHargaProduk;
                }
                return sum;
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs totalPotonganChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TotalPotongan);
        public Int32 TotalPotongan
        {
            get
            {
                Int32 sum = 0;
                foreach (TransaksiLayananViewModel tl in transaksiLayanans.Where(tl => !tl.IsBatal.DataValue))
                {
                    sum += tl.PotonganPromo.DataValue;
                }
                foreach (TransaksiProdukViewModel tp in transaksiProduks.Where(tp => !tp.IsBatal.DataValue))
                {
                    sum += tp.PotonganHarga.DataValue;
                }
                return sum;
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs totalPembayaranChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TotalPembayaran);
        public Int32 TotalPembayaran
        {
            get
            {
                Int32 sum = 0;
                foreach (TransaksiPembayaranViewModel tb in transaksiPembayarans)
                {
                    sum += tb.NominalPembayaran.DataValue;
                }
                return sum;
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs totalHargaChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.TotalHarga);
        public Int32 TotalHarga
        {
            get
            {
                return SubTotalHarga - TotalPotongan;
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs kembalianChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.Kembalian);
        public Int32 Kembalian
        {
            get
            {
                return TotalPembayaran - TotalHarga;
            }
        }

        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs statusTransaksiChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.StatusTransaksi);
        public int StatusTransaksi
        {
            get
            {
                int retval = 0;
                if (isBatal.DataValue)
                {
                    retval = STATUS_TRANSAKSI_CANCELLED;
                }
                else if (WaktuSelesai.DataValue == null)
                {
                    retval = STATUS_TRANSAKSI_ON;
                }
                else
                {
                    retval = STATUS_TRANSAKSI_OFF;
                }
                return retval;
            }
        }

        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs isAllFinishedChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IsAllFinished);
        public bool IsAllFinished
        {
            get
            {
                bool retval = true;
                foreach (var tlvm in transaksiLayanans)
                {
                    if (tlvm.StatusTransaksiLayanan != TransaksiLayananViewModel.STATUS_TRANSAKSILAYANAN_FINISHED &&
                        tlvm.StatusTransaksiLayanan != TransaksiLayananViewModel.STATUS_TRANSAKSILAYANAN_CANCELLED)
                    {
                        retval = false;
                        break;
                    }
                }
                return retval;
            }
        }
        #endregion

        #endregion

        #region PublicMethods
        public void WorkspacePreSave()
        {
            for (int i = transaksiLayanans.Count -1; i >= 0; i--)
			{
                if (!transaksiLayanans[i].IdLayanan.DataValue.HasValue && !transaksiLayanans[i].IdKaryawan.DataValue.HasValue) {
                    transaksiLayanans.RemoveAt(i);
                }
			}

            for (int i = transaksiProduks.Count -1; i >= 0; i--)
            {
                if (!transaksiProduks[i].IdJenisStok.DataValue.HasValue && !transaksiProduks[i].IdKaryawan.DataValue.HasValue)
                {
                    transaksiProduks.RemoveAt(i);
                }
            }
        }
        public void WorkspaceSave()
        {
            //EndEdit();
            //WorkspacePreSave();
            IsBusy = true;
            transaksiProvider.LazySaveTransaksi(this, PostSaveTransaksi);
        }
        public void WorkspaceSaveAndPay()
        {
            //EndEdit();
            //WorkspacePreSave();
            IsBusy = true;
            transaksiProvider.LazySaveTransaksi(this, PostSaveAndPayTransaksi);
        }
        public void WorkspaceSaveAndExit()
        {
            //EndEdit();
            //WorkspacePreSave();
            IsBusy = true;
            transaksiProvider.LazySaveTransaksi(this, PostSaveAndExitTransaksi);
        }
        public void WorkspacePay()
        {
            //filtering, yang tidak batal saja
            transaksiLayanansCV.Filter = item =>
            {
                TransaksiLayananViewModel tlvm = item as TransaksiLayananViewModel;
                return !tlvm.IsBatal.DataValue;
            };
            transaksiProduksCV.Filter = item =>
            {
                TransaksiProdukViewModel tpvm = item as TransaksiProdukViewModel;
                return !tpvm.IsBatal.DataValue;
            };
            bool? result = uiVisualizerService.ShowDialog("TransaksiPayPopup", this);
            if (result.HasValue && result.Value)
            {
            }
            else
            {
                if (IsDirty)
                {
                    WorkspaceSave();
                }
            }
            transaksiLayanansCV.Filter = null;
            transaksiProduksCV.Filter = null;
        }
        public void WorkspaceRefresh()
        {
            EndEdit();
            SynchToThumbnail(loadedTransaksiThumbnail);
            List<int> updatedIDs = new List<int>();
            foreach (var tl in transaksiLayanans)
            {
                if (!updatedIDs.Contains(tl.IdKaryawan.DataValue.Value))
                {
                    Mediator.Instance.NotifyColleagues<int>("TryRefreshKaryawanThumbnail", tl.IdKaryawan.DataValue.Value);
                    updatedIDs.Add(tl.IdKaryawan.DataValue.Value);
                }
            }
            CurrentViewMode = ViewMode.EditMode;
            isCollectionsChanged = false;
            BeginEdit();
            IsBusy = false;
        }
        public void WorkspaceExit()
        {
            Mediator.Instance.NotifyColleagues<TransaksiThumbnailViewModel>(
                "DeactivateTransaksiDetail", loadedTransaksiThumbnail);
            this.loadedTransaksiThumbnail = null;
        }

        public void PopupPayFinish()
        {
            //EndEdit();
            IsBusy = true;
            transaksiProvider.LazySavePembayaran(this, PostPayFinishTransaksi);
        }
        public void PopupPayExit()
        {
            //EndEdit();
            IsBusy = true;
            transaksiProvider.LazySaveTransaksi(this, PostPayExitTransaksi);
        }
        public void PopupExit()
        {
            CloseActivePopUpCommand.Execute(true);
        }

        #region PublicMethods.ChildCreator
        public TransaksiLayananViewModel ForceCreateChildTransaksiLayananVM()
        {
            return new TransaksiLayananViewModel(
                messageBoxService,
                uiVisualizerService,
                referenceProvider);
        }
        public TransaksiProdukViewModel ForceCreateChildTransaksiProdukVM()
        {
            return new TransaksiProdukViewModel(
                messageBoxService,
                uiVisualizerService,
                referenceProvider);
        }
        public TransaksiPembayaranViewModel ForceCreateChildTransaksiPembayaranVM()
        {
            return new TransaksiPembayaranViewModel(
                messageBoxService,
                uiVisualizerService,
                referenceProvider);
        }
        #endregion
        #endregion

        #region CommandHandlers
        #region CommandHandlers.Editors
        /// <summary>
        /// </summary>
        private bool CanExecuteKonsumenSelectCommand(Object args)
        {
            return !isBusy 
                && IdTransaksi.DataValue == 0 
                && CurrentViewMode == ViewMode.AddMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteKonsumenSelectCommand(Object args)
        {
            KonsumenSelectViewModel konsumenSelectViewModel = new KonsumenSelectViewModel(
                messageBoxService,
                uiVisualizerService,
                referenceProvider);
            bool? result = uiVisualizerService.ShowDialog("KonsumenSelectPopup", konsumenSelectViewModel);
            if (result.HasValue && result.Value && konsumenSelectViewModel.KonsumensCV.CurrentItem != null)
            {
                Console.WriteLine("masukkk");
                KonsumenThumbnailViewModel ktvm = (KonsumenThumbnailViewModel)
                    konsumenSelectViewModel.KonsumensCV.CurrentItem;
                this.IdKonsumen.DataValue = ktvm.IdKonsumen;
                this.NamaKonsumen = ktvm.Nama;
                this.AlamatKonsumen = ktvm.Alamat;
                this.TeleponKonsumen = ktvm.Telepon;
            }
        }
        
        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiLayananAddCommand(Object args)
        {
            return !isBusy 
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiLayananAddCommand(Object args)
        {
            TransaksiLayananViewModel tlvm = new TransaksiLayananViewModel(
                messageBoxService,
                uiVisualizerService,
                referenceProvider);
            tlvm.WaktuBuat.DataValue = DateTime.Now;
            tlvm.BeginEdit();
            TransaksiLayanans.Add(tlvm);
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiLayananCancelCommand(Object args)
        {
            return !isBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiLayananCancelCommand(Object args)
        {
            TransaksiLayananViewModel tlvm = args as TransaksiLayananViewModel;
            if (transaksiLayanansCV.Contains(tlvm))
            {
                if (tlvm.IdTransaksiLayanan.DataValue != 0 
                    && tlvm.CurrentViewMode != ViewMode.AddMode)
                {
                    if (tlvm.StatusTransaksiLayanan != TransaksiLayananViewModel.STATUS_TRANSAKSILAYANAN_CANCELLED)
                    {
                        CustomDialogResults result = messageBoxService.ShowOkCancel(
                            "Batalkan transaksi layanan?", CustomDialogIcons.Question);
                        if (result == CustomDialogResults.OK)
                        {
                            tlvm.WaktuSelesai.DataValue = DateTime.Now;
                            tlvm.IsBatal.DataValue = true;
                        }
                    }
                    else
                    {
                        tlvm.WaktuSelesai.DataValue = null;
                        tlvm.IsBatal.DataValue = false;
                    }
                }
                else
                {
                    transaksiLayanans.Remove(tlvm);
                }
            }
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiProdukAddCommand(Object args)
        {
            return !isBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiProdukAddCommand(Object args)
        {
            TransaksiProdukViewModel tpvm = new TransaksiProdukViewModel(
                messageBoxService,
                uiVisualizerService,
                referenceProvider);
            tpvm.JumlahProduk.DataValue = 1;
            tpvm.BeginEdit();
            TransaksiProduks.Add(tpvm);
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiProdukCancelCommand(Object args)
        {
            return !isBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiProdukCancelCommand(Object args)
        {
            TransaksiProdukViewModel tpvm = args as TransaksiProdukViewModel;
            if (transaksiProduksCV.Contains(tpvm))
            {
                if (tpvm.IdTransaksiProduk.DataValue != 0 
                    && tpvm.CurrentViewMode != ViewMode.AddMode)
                {
                    if (tpvm.StatusTransaksiProduk != TransaksiProdukViewModel.STATUS_TRANSAKSIPRODUK_CANCELLED)
                    {
                        CustomDialogResults result = messageBoxService.ShowOkCancel(
                            "Batalkan transaksi produk?", CustomDialogIcons.Question);
                        if (result == CustomDialogResults.OK)
                        {
                            tpvm.WaktuBatal.DataValue = DateTime.Now;
                            tpvm.IsBatal.DataValue = true;
                        }
                    }
                    else
                    {
                        tpvm.WaktuBatal.DataValue = null;
                        tpvm.IsBatal.DataValue = false;
                    }
                }
                else
                {
                    transaksiProduks.Remove(tpvm);
                }
            }
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiPembayaranAddCommand(Object args)
        {
            return !isBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiPembayaranAddCommand(Object args)
        {
            TransaksiPembayaranViewModel tbvm = new TransaksiPembayaranViewModel(
                messageBoxService,
                uiVisualizerService,
                referenceProvider);
            transaksiPembayarans.Add(tbvm);
            tbvm.IdJenisPembayaran.DataValue = 1;
            tbvm.NominalPembayaran.DataValue = TotalHarga - TotalPembayaran;
            tbvm.BeginEdit();
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiPembayaranCancelCommand(Object args)
        {
            return !isBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiPembayaranCancelCommand(Object args)
        {
            TransaksiPembayaranViewModel tbvm = args as TransaksiPembayaranViewModel;
            if (transaksiPembayaransCV.Contains(tbvm))
            {
                if (tbvm.IdTransaksiPembayaran.DataValue != 0)
                {
                    isCollectionsChanged = true;
                }
                transaksiPembayarans.Remove(tbvm);
            }
        }
        #endregion

        #region CommandHandlers.Finalizers
        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiSaveCommand(Object args)
        {
            return !isBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiSaveCommand(Object args)
        {
            if (IsDirty) 
            {
                WorkspacePreSave();
                if (IsValid)
                {
                    //TODO, save to database;
                    WorkspaceSave();
                }
                else
                {
                    //TODO:
                    messageBoxService.ShowError("Gagal save, data tidak valid");
                }
            }
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiPayCommand(Object args)
        {
            return !isBusy 
                && IsAllFinished
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiPayCommand(Object args)
        {
            if (IsDirty)
            {
                WorkspacePreSave();
                if (IsValid)
                {
                    WorkspaceSaveAndPay();
                }
                else
                {
                    messageBoxService.ShowError("gagal bayar, not valid");
                }
            }
            else
            {
                WorkspacePay();
            }
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiCancelCommand(Object args)
        {
            return !isBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiCancelCommand(Object args)
        {
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiPayFinishCommand(Object args)
        {
            return !IsBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON 
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiPayFinishCommand(Object args)
        {
            if (Kembalian >= 0)
            {
                CustomDialogResults result = messageBoxService.ShowOkCancel("Lakukan Pembayaran?", CustomDialogIcons.Question);
                if (result == CustomDialogResults.OK)
                {
                    PopupPayFinish();
                }
            }
            else
            {
                messageBoxService.ShowError("Uang tidak mencukupi!");
            }
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiPayExitCommand(Object args)
        {
            return true;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiPayExitCommand(Object args)
        {
            if (IsDirty
                && !IsBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode)
            {
                PopupPayExit();
            }
            else
            {
                PopupExit();
            }
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiExitCommand(Object args)
        {
            return true;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiExitCommand(Object args)
        {
            if (IsDirty
                && !IsBusy
                && StatusTransaksi == STATUS_TRANSAKSI_ON
                && CurrentViewMode != ViewMode.ViewOnlyMode)
            {
                CustomDialogResults result =
                    messageBoxService.ShowYesNoCancel("Simpan perubahan?",
                        CustomDialogIcons.Question);
                if (result == CustomDialogResults.Yes)
                {
                    WorkspacePreSave();
                    if (IsValid)
                    {
                        WorkspaceSaveAndExit();
                    }
                    else
                    {
                        //TODO:
                        messageBoxService.ShowError("Gagal save, not valid");
                    }
                }
                else if (result == CustomDialogResults.No)
                {
                    WorkspaceExit();
                }
                else if (result == CustomDialogResults.Cancel)
                {
                    //do nothing
                }
                else
                {
                    Console.WriteLine("wah2 gawat");
                }
            }
            else
            {
                WorkspaceExit();
            }
        }
        #endregion
        #endregion

        #region MediatorMessageSinks
        [MediatorMessageSink("SummaryChangeMessage")]
        private void SummaryChangeMessage(Boolean dummy)
        {
            NotifyPropertyChanged(subTotalHargaChangeArgs);
            NotifyPropertyChanged(totalPotonganChangeArgs);
            NotifyPropertyChanged(totalHargaChangeArgs);
            NotifyPropertyChanged(totalPembayaranChangeArgs);
            NotifyPropertyChanged(kembalianChangeArgs);
        }

        [MediatorMessageSink("LoadTransaksiThumbnailToWorkspace")]
        private void LoadTransaksiThumbnailToWorkspace(TransaksiThumbnailViewModel ttvm)
        {
            LoadTransaksiThumbnailInternal(ttvm);
        }

        [MediatorMessageSink("TryCloseTransaksiWorkspace")]
        private void TryCloseTransaksiWorkspace(TransaksiThumbnailViewModel ttvm)
        {
            if (ttvm.Equals(loadedTransaksiThumbnail))
            {
                TransaksiExitCommand.Execute(null);
            }
        }
        [MediatorMessageSink("TryRemoveTransaksiLayanan")]
        private void TryRemoveTransaksiLayanan(TransaksiLayananViewModel tlvm)
        {
            TransaksiLayananCancelCommand.Execute(tlvm);
        }
        [MediatorMessageSink("TryRemoveTransaksiProduk")]
        private void TryRemoveTransaksiProduk(TransaksiProdukViewModel tpvm)
        {
            TransaksiProdukCancelCommand.Execute(tpvm);
        }
        [MediatorMessageSink("TryRemoveTransaksiPembayaran")]
        private void TryRemoveTransaksiPembayaran(TransaksiPembayaranViewModel tbvm)
        {
            TransaksiPembayaranCancelCommand.Execute(tbvm);
        }
        #endregion

        #region PrivateMethods
        #region PrivateMethods.OnViewLoaded
        private void ViewAwareStatusService_ViewLoaded()
        {
            var view = viewAwareStatusService.View;
            IWorkSpaceAware workspaceData = (IWorkSpaceAware)view;
            LoadTransaksiThumbnailInternal((TransaksiThumbnailViewModel)workspaceData.WorkSpaceContextualData.DataValue);
        }
        #endregion

        #region PrivateMethods.Loader
        private void LoadTransaksiThumbnailInternal(TransaksiThumbnailViewModel ttvm)
        {
            loadedTransaksiThumbnail = ttvm;
            IdTransaksi.DataValue = ttvm.IdTransaksi;
            if (loadedTransaksiThumbnail.IdTransaksi == 0)
            {
                //transaksi baru
                SynchFromThumbnail(ttvm);
                TransaksiLayananAddCommand.Execute(null);
                TransaksiLayananAddCommand.Execute(null);
                TransaksiLayananAddCommand.Execute(null);
                BeginEdit();
            }
            else
            {
                //transaksi lama
                IsBusy = true;
                transaksiProvider.LazyLoadTransaksi(this, PostLoadTransaksi);
            }
        }
        #endregion

        #region PrivateMethods.Testers
        private bool IsCollectionsValid
        {
            get
            {
                Boolean collectionValid = true;

                foreach (TransaksiLayananViewModel transaksiLayanan in transaksiLayanans)
                {
                    try
                    {
                        collectionValid &= transaksiLayanan.IsValid;
                        if (!collectionValid)
                            break;
                    }
                    catch (Exception)
                    {
                        collectionValid = false;
                    }
                }

                foreach (TransaksiProdukViewModel transaksiProduk in transaksiProduks)
                {
                    try
                    {
                        collectionValid &= transaksiProduk.IsValid;
                        if (!collectionValid)
                            break;
                    }
                    catch (Exception)
                    {
                        collectionValid = false;
                    }
                }


                foreach (TransaksiPembayaranViewModel transaksiPembayaran in transaksiPembayarans)
                {
                    try
                    {
                        collectionValid &= transaksiPembayaran.IsValid;
                        if (!collectionValid)
                            break;
                    }
                    catch (Exception)
                    {
                        collectionValid = false;
                    }
                }
                return collectionValid;
            }
        }
        private bool IsCollectionsDirty
        {
            get
            {
                Boolean collectionsDirty = false;

                foreach (TransaksiLayananViewModel transaksiLayanan in transaksiLayanans)
                {
                    try
                    {
                        collectionsDirty |= transaksiLayanan.IsDirty;
                        if (collectionsDirty)
                            break;
                    }
                    catch (Exception)
                    {
                        collectionsDirty = true;
                    }
                }

                foreach (TransaksiProdukViewModel transaksiProduk in transaksiProduks)
                {
                    try
                    {
                        collectionsDirty |= transaksiProduk.IsDirty;
                        if (collectionsDirty)
                            break;
                    }
                    catch (Exception)
                    {
                        collectionsDirty = true;
                    }
                }


                foreach (TransaksiPembayaranViewModel transaksiPembayaran in transaksiPembayarans)
                {
                    try
                    {
                        collectionsDirty |= transaksiPembayaran.IsDirty;
                        if (collectionsDirty)
                            break;
                    }
                    catch (Exception)
                    {
                        collectionsDirty = true;
                    }
                }
                return collectionsDirty;
            }
        }
        #endregion

        #region PrivateMethods.PostSaver
        private void PostSaveTransaksi(TransaksiViewModel tvm)
        {
            if (loadedTransaksiThumbnail == null)
            {
                //do nothing, window dah closed
            }
            else if (tvm != null)
            {
                //tidak ada masalah dalam saving
                WorkspaceRefresh();
            }
            else
            {
                messageBoxService.ShowError("Gagal saving, coba lagi");
                IsBusy = false;
            }
        }
        private void PostSaveAndPayTransaksi(TransaksiViewModel tvm)
        {
            if (loadedTransaksiThumbnail == null)
            {
            }
            else if (tvm != null)
            {
                //tidak ada masalah dalam saving
                WorkspaceRefresh();
                WorkspacePay();
            }
            else
            {
                messageBoxService.ShowError("Gagal saving, coba lagi");
                IsBusy = false;
            }
        }
        private void PostSaveAndExitTransaksi(TransaksiViewModel tvm)
        {
            if (loadedTransaksiThumbnail == null)
            {
            }
            else if (tvm != null)
            {
                WorkspaceRefresh();
                WorkspaceExit();
            }
            else
            {
                messageBoxService.ShowError("Gagal saving, coba lagi");
                IsBusy = false;
            }
        }
        #endregion

        #region PrivateMethods.PostLoader
        private void PostLoadTransaksi(TransaksiViewModel tvm)
        {
            if (loadedTransaksiThumbnail == null)
            {
            }
            else if (tvm != null)
            {
                SynchToThumbnail(loadedTransaksiThumbnail);
                List<int> updatedIDs = new List<int>();
                foreach (var tl in transaksiLayanans)
                {
                    if (!updatedIDs.Contains(tl.IdKaryawan.DataValue.Value))
                    {
                        Mediator.Instance.NotifyColleagues<int>("TryRefreshKaryawanThumbnail", tl.IdKaryawan.DataValue.Value);
                        updatedIDs.Add(tl.IdKaryawan.DataValue.Value);
                    }
                }
                if (waktuSelesai.DataValue == null)
                {
                    CurrentViewMode = ViewMode.EditMode;
                    isCollectionsChanged = false;
                    BeginEdit();
                }
                else
                {
                    CurrentViewMode = ViewMode.ViewOnlyMode;
                }
                IsBusy = false;
            }
            else
            {
                messageBoxService.ShowError("Gagal load, coba lagi");
                IsBusy = false;
                BeginEdit();
            }
        }
        #endregion

        #region PrivateMethods.PostPayer
        private void PostPayFinishTransaksi(TransaksiViewModel tvm)
        {
            if (loadedTransaksiThumbnail == null)
            {
            }
            else if (tvm != null)
            {
                EndEdit();
                SynchToThumbnail(loadedTransaksiThumbnail);
                List<int> updatedIDs = new List<int>();
                foreach (var tl in transaksiLayanans)
                {
                    if (!updatedIDs.Contains(tl.IdKaryawan.DataValue.Value))
                    {
                        Mediator.Instance.NotifyColleagues<int>("TryRefreshKaryawanThumbnail", tl.IdKaryawan.DataValue.Value);
                        updatedIDs.Add(tl.IdKaryawan.DataValue.Value);
                    }
                }
                CurrentViewMode = ViewMode.ViewOnlyMode;
                isCollectionsChanged = false;
                IsBusy = false;
                PopupExit();
            }
            else
            {
                messageBoxService.ShowError("gagal bayar, coba lagi");
                IsBusy = false;
            }
        }
        private void PostPayExitTransaksi(TransaksiViewModel tvm)
        {
            if (loadedTransaksiThumbnail == null)
            {
            }
            else if (tvm != null)
            {
                //tidak ada masalah dalam payment
                WorkspaceRefresh();
                PopupExit();
            }
            else
            {
                messageBoxService.ShowError("gagal saving, coba lagi");
                IsBusy = false;
            }
        }
        #endregion

        #region PrivateMethods.Synchronizer
        private void SynchFromThumbnail(TransaksiThumbnailViewModel ttvm)
        {
            IdTransaksi.DataValue = ttvm.IdTransaksi;
            IdKonsumen.DataValue = ttvm.IdKonsumen;
            NamaKonsumen = ttvm.NamaKonsumen;
            AlamatKonsumen = ttvm.AlamatKonsumen;
            TeleponKonsumen = ttvm.TeleponKonsumen;
            IdCabang.DataValue = ttvm.IdCabang;
            WaktuBuat.DataValue = ttvm.WaktuBuat;
            WaktuSelesai.DataValue = ttvm.WaktuSelesai;
            KoreksiHarga.DataValue = ttvm.KoreksiHarga;
            IsBatal.DataValue = ttvm.IsBatal;

            TransaksiLayanans.Clear();
            TransaksiLayananViewModel tlvm = null;
            foreach (TransaksiLayananThumbnailViewModel tltvm in ttvm.TransaksiLayanans)
            {
                tlvm = new TransaksiLayananViewModel(
                    messageBoxService,
                    uiVisualizerService,
                    referenceProvider);
                tlvm.IdTransaksiLayanan.DataValue = tltvm.IdTransaksiLayanan;
                tlvm.IdTransaksi.DataValue = tltvm.IdTransaksi;
                tlvm.IdLayanan.DataValue = tltvm.IdLayanan;
                tlvm.NamaLayanan = tltvm.NamaLayanan;
                tlvm.HargaLayanan = tltvm.HargaLayanan;
                tlvm.IdKaryawan.DataValue = tltvm.IdKaryawan;
                tlvm.NamaKaryawan = tltvm.NamaKaryawan;
                tlvm.KomisiKaryawan = tltvm.KomisiKaryawan;
                tlvm.NamaPromo.DataValue = tltvm.NamaPromo;
                tlvm.PotonganPromo.DataValue = tltvm.PotonganPromo;
                tlvm.NilaiKepuasan.DataValue = tltvm.NilaiKepuasan;
                tlvm.NamaFreeGift.DataValue = tltvm.NamaFreeGift;
                tlvm.IdJenisStok.DataValue = tltvm.IdJenisStok;
                tlvm.NamaJenisStok = tltvm.NamaJenisStok;
                tlvm.JumlahFreeGift.DataValue = tltvm.JumlahFreeGift;
                tlvm.WaktuBuat.DataValue = tltvm.WaktuBuat;
                tlvm.WaktuTunggu.DataValue = tltvm.WaktuTunggu;
                tlvm.WaktuMulai.DataValue = tltvm.WaktuMulai;
                tlvm.WaktuSelesai.DataValue = tltvm.WaktuSelesai;
                tlvm.IsBatal.DataValue = tltvm.IsBatal;
                TransaksiLayanans.Add(tlvm);
            }

            TransaksiProduks.Clear();
            TransaksiProdukViewModel tpvm = null;
            foreach (TransaksiProdukThumbnailViewModel tptvm in ttvm.TransaksiProduks)
            {
                tpvm = new TransaksiProdukViewModel(
                    messageBoxService,
                    uiVisualizerService,
                    referenceProvider);
                tpvm.IdTransaksiProduk.DataValue = tptvm.IdTransaksiProduk;
                tpvm.IdTransaksi.DataValue = tptvm.IdTransaksi;
                tpvm.IdJenisStok.DataValue = tptvm.IdJenisStok;
                tpvm.NamaJenisStok = tptvm.NamaJenisStok;
                tpvm.IdKaryawan.DataValue = tptvm.IdKaryawan;
                tpvm.NamaKaryawan = tptvm.NamaKaryawan;
                tpvm.JumlahProduk.DataValue = tptvm.JumlahProduk;
                tpvm.HargaProduk.DataValue = tptvm.HargaProduk;
                tpvm.PotonganHarga.DataValue = tptvm.PotonganHarga;
                tpvm.KomisiKaryawan.DataValue = tptvm.KomisiKaryawan;
                tpvm.WaktuBatal.DataValue = tptvm.WaktuBatal;
                tpvm.IsBatal.DataValue = tptvm.IsBatal;
                TransaksiProduks.Add(tpvm);
            }

            TransaksiPembayarans.Clear();
            TransaksiPembayaranViewModel tbvm = null;
            foreach (TransaksiPembayaranThumbnailViewModel tbtvm in ttvm.TransaksiPembayarans)
            {
                tbvm = new TransaksiPembayaranViewModel(
                    messageBoxService,
                    uiVisualizerService,
                    referenceProvider);
                tbvm.IdTransaksiPembayaran.DataValue = tbtvm.IdTransaksiPembayaran;
                tbvm.IdTransaksi.DataValue = tbtvm.IdTransaksi;
                tbvm.IdJenisPembayaran.DataValue = tbtvm.IdJenisPembayaran;
                tbvm.NominalPembayaran.DataValue = tbtvm.NominalPembayaran;
                TransaksiPembayarans.Add(tbvm);
            }
        }
        private void SynchToThumbnail(TransaksiThumbnailViewModel ttvm)
        {
            ttvm.IdTransaksi = idTransaksi.DataValue;
            ttvm.IdKonsumen = idKonsumen.DataValue;
            ttvm.NamaKonsumen = namaKonsumen;
            ttvm.AlamatKonsumen = alamatKonsumen;
            ttvm.TeleponKonsumen = teleponKonsumen;
            ttvm.IdCabang = idCabang.DataValue;
            ttvm.WaktuBuat = waktuBuat.DataValue;
            ttvm.WaktuSelesai = waktuSelesai.DataValue;
            ttvm.KoreksiHarga = koreksiHarga.DataValue;
            ttvm.IsBatal = isBatal.DataValue;

            ttvm.TransaksiLayanans = new DispatcherNotifiedObservableCollection<TransaksiLayananThumbnailViewModel>();
            TransaksiLayananThumbnailViewModel tltvm = null;
            foreach (TransaksiLayananViewModel tlvm in transaksiLayanans)
            {
                tltvm = new TransaksiLayananThumbnailViewModel();
                tltvm.IdTransaksiLayanan = tlvm.IdTransaksiLayanan.DataValue;
                tltvm.IdTransaksi = tlvm.IdTransaksi.DataValue;
                tltvm.IdLayanan = tlvm.IdLayanan.DataValue;
                tltvm.NamaLayanan = tlvm.NamaLayanan;
                tltvm.HargaLayanan = tlvm.HargaLayanan;
                tltvm.IdKaryawan = tlvm.IdKaryawan.DataValue;
                tltvm.NamaKaryawan = tlvm.NamaKaryawan;
                tltvm.KomisiKaryawan = tlvm.KomisiKaryawan;
                tltvm.NamaPromo = tlvm.NamaPromo.DataValue;
                tltvm.PotonganPromo = tlvm.PotonganPromo.DataValue;
                tltvm.NilaiKepuasan = tlvm.NilaiKepuasan.DataValue;
                tltvm.NamaFreeGift = tlvm.NamaFreeGift.DataValue;
                tltvm.IdJenisStok = tlvm.IdJenisStok.DataValue;
                tltvm.NamaJenisStok = tlvm.NamaJenisStok;
                tltvm.JumlahFreeGift = tlvm.JumlahFreeGift.DataValue;
                tltvm.WaktuBuat = tlvm.WaktuBuat.DataValue;
                tltvm.WaktuTunggu = tlvm.WaktuTunggu.DataValue;
                tltvm.WaktuMulai = tlvm.WaktuMulai.DataValue;
                tltvm.WaktuSelesai = tlvm.WaktuSelesai.DataValue;
                tltvm.IsBatal = tlvm.IsBatal.DataValue;
                ttvm.TransaksiLayanans.Add(tltvm);
            }
            ttvm.TransaksiLayanansCV = CollectionViewSource.GetDefaultView(ttvm.TransaksiLayanans);

            ttvm.TransaksiProduks = new DispatcherNotifiedObservableCollection<TransaksiProdukThumbnailViewModel>();
            TransaksiProdukThumbnailViewModel tptvm = null;
            foreach (TransaksiProdukViewModel tpvm in transaksiProduks)
            {
                tptvm = new TransaksiProdukThumbnailViewModel();
                tptvm.IdTransaksiProduk = tpvm.IdTransaksiProduk.DataValue;
                tptvm.IdTransaksi = tpvm.IdTransaksi.DataValue;
                tptvm.IdJenisStok = tpvm.IdJenisStok.DataValue;
                tptvm.NamaJenisStok = tpvm.NamaJenisStok;
                tptvm.IdKaryawan = tpvm.IdKaryawan.DataValue;
                tptvm.NamaKaryawan = tpvm.NamaKaryawan;
                tptvm.JumlahProduk = tpvm.JumlahProduk.DataValue;
                tptvm.HargaProduk = tpvm.HargaProduk.DataValue;
                tptvm.PotonganHarga = tpvm.PotonganHarga.DataValue;
                tptvm.KomisiKaryawan = tpvm.KomisiKaryawan.DataValue;
                ttvm.TransaksiProduks.Add(tptvm);
            }
            ttvm.TransaksiProduksCV = CollectionViewSource.GetDefaultView(ttvm.TransaksiProduks);

            ttvm.TransaksiPembayarans = new DispatcherNotifiedObservableCollection<TransaksiPembayaranThumbnailViewModel>();
            TransaksiPembayaranThumbnailViewModel tbtvm = null;
            foreach (TransaksiPembayaranViewModel tbvm in transaksiPembayarans)
            {
                tbtvm = new TransaksiPembayaranThumbnailViewModel();
                tbtvm.IdTransaksiPembayaran = tbvm.IdTransaksiPembayaran.DataValue;
                tbtvm.IdTransaksi = tbvm.IdTransaksi.DataValue;
                tbtvm.IdJenisPembayaran = tbvm.IdJenisPembayaran.DataValue;
                tbtvm.NominalPembayaran = tbvm.NominalPembayaran.DataValue;
                ttvm.TransaksiPembayarans.Add(tbtvm);
            }
            ttvm.TransaksiPembayaransCV = CollectionViewSource.GetDefaultView(ttvm.TransaksiPembayarans);
        }
        #endregion
        #endregion

        #region Overrides
        static PropertyChangedEventArgs isValidChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IsValid);
        public override bool IsValid
        {
            get
            {
                //return base.IsValid and use DataWrapperHelper, if you are
                //using DataWrappers
                return base.IsValid &&
                    DataWrapperHelper.AllValid(cachedListOfDataWrappers) &&
                    IsCollectionsValid;
            }

        }
        
        static PropertyChangedEventArgs isDirtyChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IsDirty);
        public bool IsDirty 
        {
            get
            {
                return DataWrapperHelper2.SomeDirty(cachedListOfDataWrappers) ||
                    isCollectionsChanged ||
                    IsCollectionsDirty;
            }
        }

        public override string ToString()
        {
            return String.Format("TransaksiViewModel {0}", this.idTransaksi);
        }
        #endregion

        #region EditableValidatingViewModelBase overrides
        protected override void OnBeginEdit()
        {
            base.OnBeginEdit();
            //Now walk the list of properties in the OrderViewModel
            //and call BeginEdit() on all Cinch.DataWrapper<T>s.
            //we can use the Cinch.DataWrapperHelper class for this
            DataWrapperHelper.SetBeginEdit(cachedListOfDataWrappers);
            foreach (var item in transaksiLayanans)
            {
                item.BeginEdit();
            }
            foreach (var item in transaksiProduks)
            {
                item.BeginEdit();
            }
            foreach (var item in transaksiPembayarans)
            {
                item.BeginEdit();
            }
        }

        /// <summary>
        /// Override hook which allows us to also put any child 
        /// EditableValidatingViewModelBase objects into the EndEdit state
        /// </summary>
        protected override void OnEndEdit()
        {
            base.OnEndEdit();
            //Now walk the list of properties in the OrderViewModel
            //and call CancelEdit() on all Cinch.DataWrapper<T>s.
            //we can use the Cinch.DataWrapperHelper class for this
            DataWrapperHelper.SetEndEdit(cachedListOfDataWrappers);
            foreach (var item in transaksiLayanans)
            {
                item.EndEdit();
            }
            foreach (var item in transaksiProduks)
            {
                item.EndEdit();
            }
            foreach (var item in transaksiPembayarans)
            {
                item.EndEdit();
            }
        }

        /// <summary>
        /// Override hook which allows us to also put any child 
        /// EditableValidatingViewModelBase objects into the CancelEdit state
        /// </summary>
        protected override void OnCancelEdit()
        {
            base.OnCancelEdit();
            //Now walk the list of properties in the OrderViewModel
            //and call CancelEdit() on all Cinch.DataWrapper<T>s.
            //we can use the Cinch.DataWrapperHelper class for this
            DataWrapperHelper.SetCancelEdit(cachedListOfDataWrappers);
            foreach (var item in transaksiLayanans)
            {
                item.CancelEdit();
            }
            foreach (var item in transaksiProduks)
            {
                item.CancelEdit();
            }
            foreach (var item in transaksiPembayarans)
            {
                item.CancelEdit();
            }
        }
        #endregion
    }
}
